//! 栈操作指令编码模块
//! 
//! 实现 8086 栈操作指令：PUSH, POP

use crate::ast::Operand;
use crate::error::{AssemblerError, Result};
use super::registers::RegisterEncoding;

/// 栈操作指令编码器
pub struct StackEncoder;

impl StackEncoder {
    /// 编码栈操作指令
    pub fn encode(&self, instruction: &str, operands: &[Operand]) -> Result<Vec<u8>> {
        match instruction {
            "推入" => self.encode_push(operands),
            "弹出" => self.encode_pop(operands),
            _ => Err(AssemblerError::CodeGenError {
                message: format!("未知的栈操作指令: {}", instruction),
            }),
        }
    }

    /// 编码推入指令
    fn encode_push(&self, operands: &[Operand]) -> Result<Vec<u8>> {
        if operands.len() != 1 {
            return Err(AssemblerError::OperandError {
                message: "推入 指令需要 1 个操作数".to_string(),
                line: 0,
            });
        }

        if let Operand::Register(reg) = &operands[0] {
            let reg_code = RegisterEncoding::get_16bit_register_code(reg)
                .ok_or_else(|| AssemblerError::OperandError {
                    message: format!("无效的16位寄存器: {}", reg),
                    line: 0,
                })?;
            let opcode = 0x50 + reg_code; // PUSH reg
            Ok(vec![opcode])
        } else {
            Err(AssemblerError::OperandError {
                message: "推入暂只支持寄存器操作数".to_string(),
                line: 0,
            })
        }
    }

    /// 编码弹出指令
    fn encode_pop(&self, operands: &[Operand]) -> Result<Vec<u8>> {
        if operands.len() != 1 {
            return Err(AssemblerError::OperandError {
                message: "弹出 指令需要 1 个操作数".to_string(),
                line: 0,
            });
        }

        if let Operand::Register(reg) = &operands[0] {
            let reg_code = RegisterEncoding::get_16bit_register_code(reg)
                .ok_or_else(|| AssemblerError::OperandError {
                    message: format!("无效的16位寄存器: {}", reg),
                    line: 0,
                })?;
            let opcode = 0x58 + reg_code; // POP reg
            Ok(vec![opcode])
        } else {
            Err(AssemblerError::OperandError {
                message: "弹出暂只支持寄存器操作数".to_string(),
                line: 0,
            })
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encode_push_ax() {
        let encoder = StackEncoder;
        let operands = vec![Operand::Register("累加器".to_string())];
        let result = encoder.encode("推入", &operands).unwrap();
        // PUSH AX = 50
        assert_eq!(result, vec![0x50]);
    }

    #[test]
    fn test_encode_push_bx() {
        let encoder = StackEncoder;
        let operands = vec![Operand::Register("基址".to_string())];
        let result = encoder.encode("推入", &operands).unwrap();
        // PUSH BX = 53
        assert_eq!(result, vec![0x53]);
    }

    #[test]
    fn test_encode_pop_ax() {
        let encoder = StackEncoder;
        let operands = vec![Operand::Register("累加器".to_string())];
        let result = encoder.encode("弹出", &operands).unwrap();
        // POP AX = 58
        assert_eq!(result, vec![0x58]);
    }

    #[test]
    fn test_encode_pop_bx() {
        let encoder = StackEncoder;
        let operands = vec![Operand::Register("基址".to_string())];
        let result = encoder.encode("弹出", &operands).unwrap();
        // POP BX = 5B
        assert_eq!(result, vec![0x5B]);
    }

    #[test]
    fn test_encode_push_invalid_operand() {
        let encoder = StackEncoder;
        let operands = vec![Operand::Immediate(10)];
        let result = encoder.encode("推入", &operands);
        assert!(result.is_err());
    }

    #[test]
    fn test_encode_push_wrong_count() {
        let encoder = StackEncoder;
        let operands = vec![];
        let result = encoder.encode("推入", &operands);
        assert!(result.is_err());
    }
}

